package com.lagou.edu.spring;


import com.alibaba.druid.util.StringUtils;
import com.lagou.anno.*;
import com.lagou.edu.factory.ProxyFactory;
import com.lagou.edu.utils.TransactionManager;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import static com.lagou.edu.utils.ClassPathScannerUtil.getClassFile;


public class AnnApplicationContext {

    /**
     * 自定义注解要区分开   自定义注解不能加载 newInstance（）
     */
    public final static String PACKAGE_NAME="com.lagou.edu";

    /**
     * 缓存池，暂时不实现相互依赖的bean
     */
    private static Map<String, Object> factoryClasses = new HashMap<>();

    /**
     * 加载所有的，class 文件获取Class，排除anno下的自定义标签的Interface
     */
    private static Set<Class<?>> classSet = new HashSet();



    static {
        classSet  = getClassFile(PACKAGE_NAME);
        for (Class<?> aClass : classSet) {
            createBeanByClass(aClass);
        }
    }

    /**
     * 创建完整的bean，并放入缓存池中
     * @param aClass
     * @return
     */
    private static Object createBeanByClass(Class<?> aClass) {
        Annotation annotation = null;
        String beanName = null;
        System.out.println(aClass);
        System.out.println(factoryClasses);
        for (Annotation aClassAnnotation : aClass.getAnnotations()) {
            boolean flag = (aClassAnnotation.annotationType().getAnnotation(MyComponent.class) != null) ||( aClassAnnotation instanceof MyComponent);
            if(flag){
                annotation = aClassAnnotation;
                if(aClassAnnotation instanceof MyService){
                    beanName = ((MyService) aClassAnnotation).value();
                }else if(aClassAnnotation instanceof MyRepository){
                    beanName = ((MyRepository) aClassAnnotation).value();
                }else{
                    beanName = ((MyComponent) aClassAnnotation).value();
                }
                break;
            }
        }

        if(annotation == null){
            return null;
        }
        if (beanName != null) {
            beanName = beanName.trim();
            if(StringUtils.isEmpty(beanName)){

                Type[] interfaces = aClass.getGenericInterfaces();
                if(interfaces != null && interfaces.length > 0){
                    beanName = toLowerCaseStringFirst(((Class) interfaces[0]).getSimpleName());
                }else{
                    beanName = toLowerCaseStringFirst(aClass.getSimpleName());
                }
            }
        }

        // 判断缓存池中是否包含，包含直接获取
        for (Map.Entry<String, Object> entry : factoryClasses.entrySet()) {
            // 类型匹配
            Type[] interfaces = entry.getValue().getClass().getGenericInterfaces();
            if (null != interfaces && interfaces.length > 0) {
                for (Type thisItf : interfaces) {
                    if (thisItf.equals(aClass)) {
                        return entry.getValue();
                    }
                }
            } else if (aClass.equals(entry.getValue().getClass())) {
                return entry.getValue();
            }
        }

        // 创建bean对象,并放入缓存池中
        Object beanObj = null;
        try {
            beanObj = createBean(aClass, beanName);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        factoryClasses.put(beanName, beanObj);
        return beanObj;
    }

    /**
     * 利用反射创建bean
     * @param aClass
     * @param beanName
     * @return
     * @throws IllegalAccessException
     */
    private static Object createBean(Class<?> aClass, String beanName) throws IllegalAccessException{
        // 创建bean
        Object originBean = null;
        try {
            originBean = aClass.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
            throw new RuntimeException();
        }

        // 填充bean属性
        populateBean(originBean, aClass);

//        System.out.println("事务控制");
        // 实现事务控制的增强
        Object readyObject = initializeBean(beanName, originBean, aClass);

        // 放入一个完整的bean
        factoryClasses.put(beanName, readyObject);
        
        return readyObject ;
    }

    /**
     * 实现事务控制的增强
     *
     * @param beanName
     * @param originBean
     * @return
     */
    private static Object initializeBean(String beanName, Object originBean, Class thisClass) throws IllegalAccessException {
        // 这里只考虑在类的方法上面加事务注解,不然要考虑类&方法上的事务注解的优先级
        for (Method thisMethod : thisClass.getDeclaredMethods()) {

            // 有事务注解的方法,进行事务增强
            if (thisMethod.isAnnotationPresent(MyTransactional.class)) {

                System.out.println("获取事务管理器");
                // 获取事务管理器
                TransactionManager transactionManager = (TransactionManager) getBean("transactionManager",TransactionManager.class);

                // jdk代理
                if (thisClass.getInterfaces() != null) {
                    return ProxyFactory.createJdkProxy(transactionManager, thisClass, originBean);
                } else {
                    return ProxyFactory.createCglibProxy(transactionManager, thisClass, originBean);
                }

            }
        }


        return originBean;
    }

    /**
     * 填充bean属性
     *
     * @param originBean
     * @param thisClass
     */
    private static void populateBean(Object originBean, Class<?> thisClass) throws IllegalAccessException {
        Field[] declaredFields = thisClass.getDeclaredFields();
        for (Field thisField : declaredFields) {

            // 判断是否有需要注入的属性
            if (thisField.isAnnotationPresent(MyAutowired.class)) {
                thisField.setAccessible(true);


                Boolean producedFlag = false;

                Class<?> fieldClass = thisField.getType();

                for (Map.Entry<String, Object> entry : factoryClasses.entrySet()) {

                    // 类型匹配
                    Type[] interfaces = entry.getValue().getClass().getGenericInterfaces();
                    if (null != interfaces && interfaces.length > 0) {
                        for (Type thisItf : interfaces) {
                            if (thisItf.equals(fieldClass)) {
                                thisField.set(originBean, entry.getValue());
                                producedFlag = true;
                                break;
                            }
                        }

                    }

                }
                if (!producedFlag) {
                    thisField.set(originBean, createBeanByClass(fieldClass));
                }

            }

        }


    }

    /**
     * 将String中首字母转大写
     * @param simpleName
     * @return
     */
    private static String toLowerCaseStringFirst(String simpleName) {
        if (Character.isLowerCase(simpleName.charAt(0))) {
            return simpleName;
        } else {
            return (new StringBuilder()).append(Character.toLowerCase(simpleName.charAt(0))).append(simpleName.substring(1)).toString();
        }
    }


    public static Object getBean(String id) {

        return factoryClasses.get(id);
    }
    /**
     * 输入的id，factoryClasses，实例化工厂对象
     *
     * @param beanName
     * @param  beanClass
     * @return
     */
    public static synchronized Object getBean(String beanName, Class beanClass) throws IllegalAccessException {
        Object cacheObj = factoryClasses.get(beanName);
        if (null == cacheObj) {

        }
        return createBean(beanClass, beanName);
    }
}